<?php
namespace app\controller;

use think\facade\Db;
use think\facade\Request;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\Writer\PngWriter;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelHigh;
use Endroid\QrCode\Logo\Logo;
use ZipArchive;
use think\response\File;

class QrZipController
{
    public function export()
    {
        try {
            // $dataList = $this->getSampleData();
            
            $param = Request::param();
            $ids = $param['selectId'];
            
            $dataList = [];
            $dataList1 = Db::name('qrcode_p')
                ->field('id,qr_sn,pid')
                ->where('id','in',$ids)
                ->select()
                ->all();
            $dataList2 = Db::name('qrcode')
                ->field('id,qr_sn,pid')
                ->where('pid','in',$ids)
                ->select()
                ->all();
            foreach($dataList1 as $item1){
                $dataList[] = $item1;
            }
            foreach($dataList2 as $item2){
                $dataList[] = $item2;
            }

            
            // 循环添加url
           foreach($dataList as $key=>$item){
                // 获取当前domain
               $domain = Request::domain();
               $dataList[$key]['url'] = $domain.'/qrcode/?id='.$item['qr_sn'];
           }
          
            if (empty($dataList)) {
                throw new \Exception('没有可导出的数据');
            }

            // 修复：将简写的 throw 改为 if 判断
            if (empty($dataList)) {
                throw new \Exception('没有可导出的数据');
            }
            
            // $this->validateDataFormat($dataList);
            $qrFilePaths = $this->generateBatchQr($dataList);
            $zipFilePath = $this->createZipArchive($qrFilePaths);
            $this->cleanTempFiles($qrFilePaths);

            return $this->outputZipFile($zipFilePath);
        } catch (\Exception $e) {
            return json(['code' => 1, 'msg' => $e->getMessage()]);
        }
    }

    // 示例数据
    private function getSampleData(): array
    {
        return [
            ['id' => 5, 'name' => '1位数字', 'url' => 'https://example.com/5','pid'=>0],
            ['id' => 28, 'name' => '2位数字', 'url' => 'https://example.com/28','pid'=>1],
            ['id' => 136, 'name' => '3位数字', 'url' => 'https://example.com/136','pid'=>2],
        ];
    }

    private function validateDataFormat(array $dataList): void
    {
        foreach ($dataList as $index => $item) {
            if (!is_array($item) || !isset($item['url'], $item['id'], $item['name'])) {
                throw new \Exception("第 {$index} 条数据格式错误或缺少字段");
            }
        }
    }

    private function generateBatchQr(array $dataList): array
    {
        
        $filePaths = [];
        $tempDir = $this->getTempDir();
        
        // 修复：将简写的 throw 改为 if 判断
        if (!extension_loaded('gd')) {
            throw new \Exception('请启用PHP的GD扩展');
        }

        foreach ($dataList as $item) {
            // 生成基础二维码
            $qrCode = QrCode::create($item['url'])
                ->setEncoding(new Encoding('UTF-8'))
                ->setErrorCorrectionLevel(new ErrorCorrectionLevelHigh())
                ->setSize(300);

            // 生成完全居中的数字图片
            $numberLogoPath = $this->generateFullCenteredNumberImage($item['id'], $tempDir);

            // 嵌入数字Logo
            $logo = Logo::create($numberLogoPath)
                ->setResizeToWidth(70);

            if($item['pid']==0){
                $filename = "boxCode_{$item['id']}.png";
                $filePath = $tempDir . $filename;
                file_put_contents($filePath, (new PngWriter())->write($qrCode, $logo)->getString());
            }else{
                $filename = "boxCode{$item['pid']}goodsCode_{$item['qr_sn']}.png";
                $filePath = $tempDir . $filename;
                file_put_contents($filePath, (new PngWriter())->write($qrCode)->getString());
            }
            // 保存二维码
            // $filename = "qr_{$item['id']}_{$this->filterFilename($item['name'])}.png";
            // $filePath = $tempDir . $filename;
            // file_put_contents($filePath, (new PngWriter())->write($qrCode, $logo)->getString());

            @unlink($numberLogoPath);
            $filePaths[] = $filePath;
        }
        return $filePaths;
    }

    /**
     * 生成水平+垂直完全居中的数字图片
     */
    private function generateFullCenteredNumberImage(int $number, string $tempDir): string
    {
        $imageSize = 100;
        $image = imagecreatetruecolor($imageSize, $imageSize);

        // 白色背景
        $white = imagecolorallocate($image, 255, 255, 255);
        imagefill($image, 0, 0, $white);

        // 字体配置
        $fontPath = $this->getFontPath();
        // 修复：将简写的 throw 改为 if 判断
        if (!file_exists($fontPath)) {
            throw new \Exception("字体文件不存在：{$fontPath}");
        }

        // 动态调整字体大小
        $numberStr = (string)$number;
        switch (strlen($numberStr)) {
            case 1:
                $fontSize = 45;
                break;
            case 2:
                $fontSize = 38;
                break;
            case 3:
                $fontSize = 30;
                break;
            default:
                $fontSize = 25;
        }

        // 计算文字边界
        $bbox = imagettfbbox($fontSize, 0, $fontPath, $numberStr);
        $textWidth = $bbox[2] - $bbox[0];
        $textHeight = $bbox[1] - $bbox[7];

        // 计算居中坐标
        $x = ($imageSize - $textWidth) / 2 - $bbox[0];
        $y = ($imageSize / 2) + ($textHeight / 2) - $bbox[1];

        // 绘制数字
        $black = imagecolorallocate($image, 0, 0, 0);
        imagettftext($image, $fontSize, 0, (int)$x, (int)$y, $black, $fontPath, $numberStr);

        // 保存图片
        $imagePath = $tempDir . "num_{$number}.png";
        imagepng($image, $imagePath);
        imagedestroy($image);

        return $imagePath;
    }

    // 字体路径
    private function getFontPath(): string
    {
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            return 'C:/Windows/Fonts/simhei.ttf';
        }
         $path = dirname(__FILE__);
        // 把 /app/controller 替换为 /public/fonts
        $path = str_replace('/app/controller', '/public/fonts/simhei.ttf', $path);
        return $path;
    }

    // 创建ZIP压缩包
    private function createZipArchive(array $filePaths): string
    {
        $zip = new ZipArchive();
        $zipName = '二维码批量导出_' . date('YmdHis') . '.zip';
        $zipPath = sys_get_temp_dir() . '/' . $zipName;

        // 修复：将简写的 throw 改为 if 判断
        if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
            throw new \Exception('无法创建ZIP文件，请检查zip扩展');
        }

        foreach ($filePaths as $filePath) {
            if (file_exists($filePath)) {
                $zip->addFile($filePath, basename($filePath));
            }
        }
        $zip->close();
        
        // 修复：将简写的 throw 改为 if 判断
        if (!file_exists($zipPath)) {
            throw new \Exception('ZIP文件生成失败');
        }

        return $zipPath;
    }

    // 清理临时文件
    private function cleanTempFiles(array $filePaths): void
    {
        foreach ($filePaths as $filePath) {
            if (file_exists($filePath)) {
                @unlink($filePath);
            }
        }
        $tempDir = $this->getTempDir();
        if (is_dir($tempDir)) {
            @rmdir($tempDir);
        }
    }

    // 输出ZIP文件
    private function outputZipFile(string $zipFilePath): File
    {
        ob_end_clean();
        return (new File($zipFilePath, 200))->header([
            'Content-Type' => 'application/zip',
            'Cache-Control' => 'max-age=0',
            'Content-Disposition' => 'attachment; filename="' . basename($zipFilePath) . '"'
        ]);
    }

    // 获取临时目录
    private function getTempDir(): string
    {
        $tempDir = sys_get_temp_dir() . '/qr_batch_temp/';
        if (!is_dir($tempDir)) {
            mkdir($tempDir, 0777, true);
        }
        return $tempDir;
    }

    // 过滤文件名
    private function filterFilename(string $filename): string
    {
        return preg_replace('/[^\w\-\.]+/', '_', $filename);
    }
}